package utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import data.Carrier;
import data.CarrierType;
import data.Package;

public class HeuristicsCarrierUtils {

	CarrierUtils utils = new CarrierUtils();

	public List<Carrier> minimizeMinCapacity(List<CarrierType> carrierTypes,
			List<Carrier> carriers) {
		if (carriers.size() < 2)
			return carriers;

		List<Carrier> resultList = new ArrayList<Carrier>();
		Collections.sort(carriers, new CarrierMinCapacityComparator());
		Carrier carrierWithLargestFreePlace = carriers.get(carriers.size() - 1);

		List<Package> packagesToRemove = new ArrayList<Package>();

		for (Carrier carrier : carriers) {
			if (carrier.getName().equals(carrierWithLargestFreePlace.getName()))
				continue;
			for (Package packageToGetOut : carrierWithLargestFreePlace
					.getPackages()) {
				float weight = carrier.getWeight()
						+ packageToGetOut.getWeight();
				float capacity = carrier.getCapacity()
						+ packageToGetOut.getCapacity();
				float capMax = (float) (carrier.getType().getFieldBase() * carrier
						.getType().getMaxHeight());
				if ((weight <= carrier.getType().getMaxWeight())
						&& (capMax >= capacity)) {
					CarrierType potentialType = utils
							.getPotentialCarrierType(carrierTypes,
									packageToGetOut.getPrefferedCarrier());
					capMax = (float) (potentialType.getFieldBase() * potentialType
							.getMaxHeight());
					if ((weight <= potentialType.getMaxWeight())
							&& (capMax >= capacity)) {
						carrier.pushPackage(packageToGetOut);
						packagesToRemove.add(packageToGetOut);
						utils.updateCarrierTypeIfNecessary(carrier,
								carrierTypes);
					}
				}
			}
			for (Package packageToRemove : packagesToRemove) {
				carrierWithLargestFreePlace.popPackage(packageToRemove);
				utils.updateCarrierTypeIfNecessary(carrierWithLargestFreePlace,
						carrierTypes);
			}
		}
		for (Carrier carrier : carriers) {
			if (carrier.getCapacity() > carrier.getType().getFieldBase()
					* carrier.getType().getMaxHeight())
				System.out.println(carrier.getCapacity() + " "
						+ carrier.getType().getFieldBase()
						* carrier.getType().getMaxHeight());
			if (carrier.getPackages().size() > 0) {
				resultList.add(carrier);
			}
		}
		return resultList;
	}

	public List<Carrier> mixPackages(List<CarrierType> carrierTypes,
			List<Carrier> carriers) {
		List<Carrier> resultList = new ArrayList<Carrier>();
		Package packageFromCarrierTemp = null, packageFromMinTemp = null;
		Carrier carrierToChange = null;
		boolean isFound = false;

		Collections.sort(carriers, new CarrierMinCapacityComparator());
		Carrier carrierWithLargestFreePlace = carriers.get(carriers.size() - 1);

		for (Carrier carrier : carriers) {
			// jesli rozwazany carrier jest minimalnym to continue - bo to to
			// samo
			if (carrier.getName().equals(carrierWithLargestFreePlace.getName()))
				continue;
			for (Package packageFromMinCarrier : carrierWithLargestFreePlace
					.getPackages()) {
				for (Package packageFromCarrier : carrier.getPackages()) {
					// chcemy wrzucic mniejsze paczki na najmniejszy carrier
					// dlatego jesli paczka z obcego carriera jest wieksza to
					// continue
					if (packageFromMinCarrier.getCapacity() > packageFromCarrier
							.getCapacity())
						continue;
					// SPRAWDZAMY CZY I-ty CARRIER MOZE PRZYJAC PACZKE OD NAS
					// PRZY CZYM ODEJMUJEMY CAPACITY I WEIGHT PACZKI KTORA
					// CHCEMY
					// WYRZUCIC NA MINA
					float weight = carrier.getWeight()
							+ packageFromMinCarrier.getWeight()
							- packageFromCarrier.getWeight();
					float capacity = carrier.getCapacity()
							+ packageFromMinCarrier.getCapacity()
							- packageFromCarrier.getCapacity();
					float capMax = (float) (carrier.getType().getFieldBase() * carrier
							.getType().getMaxHeight());
					if ((weight <= carrier.getType().getMaxWeight())
							&& (capMax >= capacity)) {
						CarrierType potentialType = utils
								.getPotentialCarrierType(carrierTypes,
										packageFromMinCarrier
												.getPrefferedCarrier());
						capMax = (float) (potentialType.getFieldBase() * potentialType
								.getMaxHeight());
						if ((weight <= potentialType.getMaxWeight())
								&& (capMax >= capacity)) {
							// TERAZ CZAS SPRAWDZIC CZY MIN CARRIER MOZE PRZYJAC
							// TA PACZKE PO ODJECIU SWOJEJ

							weight = carrierWithLargestFreePlace.getWeight()
									+ packageFromCarrier.getWeight()
									- packageFromMinCarrier.getWeight();
							capacity = carrierWithLargestFreePlace
									.getCapacity()
									+ packageFromCarrier.getCapacity()
									- packageFromMinCarrier.getCapacity();
							capMax = (float) (carrierWithLargestFreePlace
									.getType().getFieldBase() * carrierWithLargestFreePlace
									.getType().getMaxHeight());
							if ((weight <= carrierWithLargestFreePlace
									.getType().getMaxWeight())
									&& (capMax >= capacity)) {
								potentialType = utils.getPotentialCarrierType(
										carrierTypes, packageFromCarrier
												.getPrefferedCarrier());
								capMax = (float) (potentialType.getFieldBase() * potentialType
										.getMaxHeight());
								if ((weight <= potentialType.getMaxWeight())
										&& (capMax >= capacity)) {
									packageFromMinTemp = packageFromMinCarrier;
									packageFromCarrierTemp = packageFromCarrier;
									carrierToChange = carrier;
									isFound = true;
									break;
								}
							}
						}
					}
				}
				if (isFound)
					break;
			}
			if (isFound)
				break;
		}
		// jesli znaleziony to aktualizujemy i ewentualnie jesli nosnik sie
		// zmienia to zmieniamy
		if (isFound) {
			carrierToChange.popPackage(packageFromCarrierTemp);
			carrierToChange.pushPackage(packageFromMinTemp);
			carrierWithLargestFreePlace.popPackage(packageFromMinTemp);
			carrierWithLargestFreePlace.pushPackage(packageFromCarrierTemp);
			utils.updateCarrierTypeIfNecessary(carrierWithLargestFreePlace,
					carrierTypes);
			utils.updateCarrierTypeIfNecessary(carrierToChange, carrierTypes);
		}

		// wrzucamy na liste wyjsciowa
		for (Carrier carrier : carriers) {
			if (carrier.getPackages().size() > 0) {
				resultList.add(carrier);
			}
		}
		return resultList;
	}
}
